package com.xrh.xdemo.service.service;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xrh.core.bean.CommonPage;
import com.xrh.core.bean.CommonResult;
import com.xrh.core.exceptions.BusinessException;
import com.xrh.core.utils.XAssert;
import com.xrh.xdemo.api.constants.LoginConstants;
import com.xrh.xdemo.api.constants.MenuTypeConstants;
import com.xrh.xdemo.api.dto.entity.SysUserDTO;
import com.xrh.xdemo.api.dto.extend.SysUserBindRoleInfoDTO;
import com.xrh.xdemo.api.dto.extend.SysUserDetailDTO;
import com.xrh.xdemo.api.dto.extend.SysUserRoleInfoDTO;
import com.xrh.xdemo.api.request.addRequest.SysUserAddRequest;
import com.xrh.xdemo.api.request.queryRequest.SysUserQueryRequest;
import com.xrh.xdemo.api.request.updateRequest.ModifyPasswordRequest;
import com.xrh.xdemo.api.request.updateRequest.SysUserUpdateRequest;
import com.xrh.xdemo.api.request.updateRequest.UserBindRolesRequest;
import com.xrh.xdemo.service.aspects.OperateTraceAspect;
import com.xrh.xdemo.service.entity.MenuEntity;
import com.xrh.xdemo.service.entity.SysUserEntity;
import com.xrh.xdemo.service.mapper.SysUserMapper;
import com.xrh.xdemo.service.utils.LoginUtils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;

@Service
public class SysUserService {

	@Resource
	SysUserMapper sysUserMapper;

	@Resource
	SysRoleService sysRoleService;
	
	@Resource
	UserVsRoleService userVsRoleService;
	
	@Resource
	MenuService menuService;
	
	/**
	 * @function 根据账号获取用户信息
	 * @param account
	 * @author 肖荣辉
	 * @date 2023年12月8日
	*/
	public SysUserEntity findSysUserByAccount(String account) {
		
		LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<SysUserEntity>();
		
		queryWrapper.eq(SysUserEntity::getAccount, account);
		
		queryWrapper.last("limit 1");
		
		return sysUserMapper.selectOne(queryWrapper);
	}
	
	/**
	 * @function 获取登录用户信息
	 * @param userId
	 * @author 肖荣辉
	 * @date 2023年12月8日
	*/
	public String getSysUserLoginInfo(Long userId) {
		
		 //若是超级管理员
        if (LoginConstants.JWT_LOGIN_SYS_ACCOUNT_ID.equals(userId)) {
            SysUserDetailDTO user = findSysUserDetailById(userId);
            return Base64.encode(ZipUtil.gzip(JSONUtil.toJsonStr(user), "utf-8"));
        }
		
		SysUserEntity entity = sysUserMapper.selectById(userId);
		
		return entity == null ? null : entity.getLoginInfo();
		
	}
	
	/**
	 * @function 根据id更新
	 * @author 肖荣辉
	 * @date 2023年12月8日
	*/
	public void updateById(SysUserEntity entity) {
		sysUserMapper.updateById(entity);
	}
	
    /**
     * @function 创建超级管理员的entity , 超级管理员不如数据库
     * @author 肖荣辉
     * @date 2020年11月4日
     */
    public SysUserEntity createAdminEntity() {
    	
		//系统配置的账号密码
		Environment environment = SpringUtil.getBean(Environment.class);
		
		//系统账号密码
		String sysAccount = environment.getProperty("sys.account");
		String sysPassword = environment.getProperty("sys.password");
		
    	SysUserEntity admin = new SysUserEntity();
        admin.setAccount(sysAccount);
        admin.setPassword(SecureUtil.md5(sysPassword));
        admin.setUserName("超级管理员");
        admin.setId(LoginConstants.JWT_LOGIN_SYS_ACCOUNT_ID);
        admin.setCreateUserId(LoginConstants.JWT_LOGIN_SYS_ACCOUNT_ID);
        admin.setEnable(1);
        admin.setBirthday(new Date());
        admin.setGender("男");

        return admin;
    }
	
	
	/**
	 * @function 新增SysUser
	 * @param sysUserAddRequest
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
    @Transactional
	public Long addSysUser(SysUserAddRequest sysUserAddRequest) {
		
		SysUserEntity sysUserEntity = findSysUserByAccount(sysUserAddRequest.getAccount());

		XAssert.isTrue(sysUserEntity == null, "账号【"+sysUserAddRequest.getAccount()+"】已被使用");
		
		sysUserEntity = new SysUserEntity();
		
		BeanUtil.copyProperties(sysUserAddRequest , sysUserEntity , CopyOptions.create().ignoreNullValue());
		
		sysUserEntity.setEnable(1);
		
		sysUserMapper.insert(sysUserEntity);
		
		userVsRoleService.resetUserBindRoles(sysUserEntity.getId(), sysUserAddRequest.getRoleIds());
		
		return sysUserEntity.getId();
	}

	/**
	 * @function 删除SysUser
	 * @param id
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
	public void deleteSysUserById(Long id) {
		
		if(id == null)
			throw new BusinessException("id不能为空");
			
		SysUserEntity sysUserEntity = sysUserMapper.selectById(id);
		
		if(sysUserEntity == null)
			throw new BusinessException("id不合法");
		
		UpdateWrapper<SysUserEntity> updateWrapper = new UpdateWrapper<>();
		updateWrapper.eq("id", id);
		
		//因为注解了@TableLogic , 自动会把删除标志位设置为1 
		sysUserMapper.delete(updateWrapper);
		
		//设置操作轨迹标题
		OperateTraceAspect.setTitle(sysUserEntity.getUserName());
		
	}

	/**
	 * @function 修改SysUser
	 * @param sysUserUpdateRequest
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
	@Transactional
	public void updateSysUser(SysUserUpdateRequest sysUserUpdateRequest) {
		
		if(sysUserUpdateRequest.getId() == null)
			throw new BusinessException("id不能为空");
		
		SysUserEntity sysUserEntity = sysUserMapper.selectById(sysUserUpdateRequest.getId());
		
		if(sysUserEntity == null)
			throw new BusinessException("id不合法");
		
		BeanUtil.copyProperties(sysUserUpdateRequest , sysUserEntity , CopyOptions.create().ignoreNullValue());
		
		sysUserMapper.updateById(sysUserEntity);
		
		userVsRoleService.resetUserBindRoles(sysUserEntity.getId(), sysUserUpdateRequest.getRoleIds());
	}
	
	/**
	 * @function 修改个人信息
	 * @param sysUserUpdateRequest
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
	public void modifyPersonInfo(SysUserUpdateRequest sysUserUpdateRequest) {
		
		if(sysUserUpdateRequest.getId() == null)
			throw new BusinessException("id不能为空");
		
		SysUserEntity sysUserEntity = sysUserMapper.selectById(sysUserUpdateRequest.getId());
		
		if(sysUserEntity == null)
			throw new BusinessException("id不合法");
		
		//和当前登录用户信息要相等
		XAssert.isTrue(LoginUtils.getUser().getId().equals(sysUserUpdateRequest.getId()), "非法操作 , 请重新登录重试!");
		
		BeanUtil.copyProperties(sysUserUpdateRequest , sysUserEntity , CopyOptions.create().ignoreNullValue());
		
		sysUserMapper.updateById(sysUserEntity);
		
	}

	/**
	 * @function 根据ID查询SysUser Entity
	 * @param id
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
	public SysUserEntity findSysUserEntityById(Long id) {
		
		if(id == null)
			throw new BusinessException("id不能为空");
		
		if(LoginConstants.JWT_LOGIN_SYS_ACCOUNT_ID.equals(id))
			return createAdminEntity();
			
		SysUserEntity sysUserEntity = sysUserMapper.selectById(id);
		
		return sysUserEntity;
	}
	
	/**
	 * @function 根据ID查询SysUser DTO
	 * @param id
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
	public SysUserDTO findSysUserById(Long id) {
		
		if(id == null)
			throw new BusinessException("id不能为空");
	
		SysUserEntity sysUserEntity = findSysUserEntityById(id);
		
		SysUserDTO  sysUserDTO = BeanUtil.toBean(sysUserEntity , SysUserDTO.class);
		
		return sysUserDTO;
	}
	
	/**
	 * @function 根据ID查询用户详情
	 * @param id
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	 */
	public SysUserDetailDTO findSysUserDetailById(Long id) {
		
		if(id == null)
			throw new BusinessException("id不能为空");
		
		SysUserEntity sysUserEntity = findSysUserEntityById(id);
		
		SysUserDTO  sysUserDTO = BeanUtil.toBean(sysUserEntity , SysUserDTO.class);
		
		SysUserDetailDTO user = BeanUtil.copyProperties(sysUserDTO, SysUserDetailDTO.class);
		
		//设置用户详情
		setUserDetail(user);
		
		return user;
	}
	
	/**
	 * @function 设置用户详情
	 * @author 肖荣辉
	 * @date 2023年12月8日
	*/
	public void setUserDetail(SysUserDetailDTO user) {
		
		if(user == null)
			return;
		
		//设置角色信息
		user.setRoleInfoList(sysRoleService.getRoleInfoDTOListByUserId(user.getId()));
		
		//用户拥有的菜单集合
		List<MenuEntity> menuList = menuService.getMenuEntitysByUserId(user.getId());
		
		//设置拥有的菜单按钮编号集合
		user.setMenuNos(CollStreamUtil.toSet(menuList, MenuEntity::getMenuNo));
		
		//设置拥有的接口地址集合
		user.setMenuUrls(menuList.stream().filter(item->MenuTypeConstants.BUTTON == item.getType() && StrUtil.isNotBlank(item.getUrl())).map(MenuEntity::getUrl).collect(Collectors.toSet()));
		
	}

	/**
	 * @function 根据SysUserQueryVo查询SysUser列表
	 * @param sysUserQueryRequest
	 * @author 肖荣辉
	 * @date 2023-12-08 15:17:26
	*/
	public CommonResult<CommonPage<SysUserDTO>> findSysUserList(SysUserQueryRequest sysUserQueryRequest) {
		
		Page<SysUserEntity> page = sysUserQueryRequest.createPage();

		QueryWrapper<SysUserEntity> queryWrapper = sysUserQueryRequest.createQuery();
		
		sysUserMapper.selectPage(page, queryWrapper);
		
		List<SysUserDTO> dtoList = BeanUtil.copyToList(page.getRecords() , SysUserDTO.class);
		
		return CommonResult.success(CommonPage.create(sysUserQueryRequest.getPageNum() , sysUserQueryRequest.getPageSize() , dtoList, page.getTotal()));
	}
	
   	/**
   	 * @function 修改密码
   	 * @param modifyPasswordRequest
   	 * @author 肖荣辉
   	 * @date 2023-12-08 15:17:26
   	 */
	public void modifyPassword(ModifyPasswordRequest modifyPasswordRequest) {
		
		if(LoginConstants.JWT_LOGIN_SYS_ACCOUNT_ID.equals(modifyPasswordRequest.getId()))
			throw new BusinessException("非法操作");
			
		SysUserEntity entity = sysUserMapper.selectById(modifyPasswordRequest.getId());
		
		XAssert.isTrue(entity != null, "用户id不合法");
		
		XAssert.isTrue(entity.getPassword().equals(modifyPasswordRequest.getOldPassword()), "原密码不正确");
		
		entity.setPassword(modifyPasswordRequest.getNewPassword());
		
		sysUserMapper.updateById(entity);
		
	}

   	/**
   	 * @function 启用禁用用户
   	 * @author 肖荣辉
   	 * @date 2023-12-08 15:17:26
   	 */
	public void enableUser(Long id , Integer enableFlag) {
		
		XAssert.isTrue(id != null, "用户id不能为空");
		
		XAssert.isTrue(enableFlag != null, "启用禁用标志不合法");
		
		enableFlag = enableFlag == 0 ? 0 : 1;
		
		SysUserEntity entity = sysUserMapper.selectById(id);
		
		XAssert.isTrue(entity != null, "用户id不合法");
		
		entity.setEnable(enableFlag);
		
		sysUserMapper.updateById(entity);
	}
	
    /**
   	 * @function 用户绑定角色
   	 * @param bindRequest
   	 * @author 肖荣辉
   	 * @date 2023-12-08 15:17:26
   	*/
	public void userBindRoles(UserBindRolesRequest userBindRolesRequest) {
		
		SysUserEntity entity = sysUserMapper.selectById(userBindRolesRequest.getUserId());
		
		XAssert.isTrue(entity != null, "用户id不合法");
		
		userVsRoleService.resetUserBindRoles(entity.getId(), userBindRolesRequest.getRoleIds());
		
	}
	
   	/**
   	 * @function 重置密码
   	 * @author 肖荣辉
   	 * @date 2023-12-08 15:17:26
   	 */
	public void resetPassword(Long id) {
		
		XAssert.isTrue(id != null, "用户id不能为空");
		
		SysUserEntity entity = sysUserMapper.selectById(id);
		
		XAssert.isTrue(entity != null, "用户id不合法");
		
		entity.setPassword(SecureUtil.md5("cool@123456"));
		
		sysUserMapper.updateById(entity);
	}
	
   	/**
   	 * @function 获取用户携带角色信息列表
   	 * @author 肖荣辉
   	 * @param sysUserQueryRequest
   	 * @date 2023-12-08 15:17:26
   	*/
	public CommonResult<CommonPage<SysUserRoleInfoDTO>> findSysUserWithRoleInfoList(SysUserQueryRequest sysUserQueryRequest) {
		
		Page<SysUserEntity> page = sysUserQueryRequest.createPage();

		QueryWrapper<SysUserEntity> queryWrapper = sysUserQueryRequest.createQuery();
		
		sysUserMapper.selectPage(page, queryWrapper);
		
		List<SysUserRoleInfoDTO> dtoList = BeanUtil.copyToList(page.getRecords() , SysUserRoleInfoDTO.class);
		
		//查询出每个用户的角色信息
		for(SysUserRoleInfoDTO dto : dtoList) {
			dto.setRoleInfoList(sysRoleService.getRoleInfoDTOListByUserId(dto.getId()));
		}
		
		return CommonResult.success(CommonPage.create(sysUserQueryRequest.getPageNum() , sysUserQueryRequest.getPageSize() , dtoList, page.getTotal()));
	}
	
   	/**
   	 * @function 获取携带绑定角色标志的用户信息列表
   	 * @author 肖荣辉
   	 * @param sysUserQueryRequest
   	 * @date 2023-12-08 15:17:26
   	 */
	public CommonResult<CommonPage<SysUserBindRoleInfoDTO>> findSysUserBindRoleInfoList(SysUserQueryRequest sysUserQueryRequest) {
		
		Long sysRoleId = sysUserQueryRequest.getSysRoleId();
		
		XAssert.isTrue(sysRoleId != null, "角色id不能为空");
		
		Page<SysUserEntity> page = sysUserQueryRequest.createPage();

		QueryWrapper<SysUserEntity> queryWrapper = sysUserQueryRequest.createQuery();
		
		boolean operateFlag = setUserQueryWrapperByBindFlag(queryWrapper, sysRoleId, sysUserQueryRequest.getBindFlag());
		
		//true : 直接返回空数组 , false : 不做任何操作
		if(operateFlag)
			return CommonResult.success(CommonPage.create(sysUserQueryRequest.getPageNum() , sysUserQueryRequest.getPageSize() , new ArrayList<SysUserBindRoleInfoDTO>(), 0));;
		
		sysUserMapper.selectPage(page, queryWrapper);
		
		List<SysUserBindRoleInfoDTO> dtoList = BeanUtil.copyToList(page.getRecords() , SysUserBindRoleInfoDTO.class);
		
		//查询出每个用户的角色信息
		for(SysUserBindRoleInfoDTO dto : dtoList) {
			
			Set<Long> roleIds = sysRoleService.getRoleIdsByUserId(dto.getId());
			
			if(CollUtil.isEmpty(roleIds)) continue;
			
			dto.setBindRoleFlag(roleIds.contains(sysRoleId));
			
		}
		
		return CommonResult.success(CommonPage.create(sysUserQueryRequest.getPageNum() , sysUserQueryRequest.getPageSize() , dtoList, page.getTotal()));
	}
	
	/**
	 * @function 根据绑定标志设置查询器参数
	 * @author 肖荣辉
	 * @date 2023年12月20日
	 * @return true : 直接返回空数组 , false : 不做任何操作
	*/
	private boolean setUserQueryWrapperByBindFlag(QueryWrapper<SysUserEntity> queryWrapper , Long sysRoleId , Boolean bindFlag) {
		
		if(bindFlag == null)
			return false;
		
		//查询到当前角色绑定的用户ids
		Set<Long> userIds = userVsRoleService.getUserIdsByRoleId(sysRoleId);
		
		//查询未绑定 , 但是userIds为空 , 证明都是未绑定的 , 直接返回
		if(!bindFlag && CollUtil.isEmpty(userIds))
			return false;
		
		if(!bindFlag && CollUtil.isNotEmpty(userIds)) {
			queryWrapper.notIn("id", userIds);
			return false;
		}
		
		//查询已绑定 , 但是userIds为空 , 证明都是未绑定的 , 返回空数组
		if(CollUtil.isEmpty(userIds))
			return true;
		
		queryWrapper.in("id", userIds);
		
		return false;
		
	}
	
}
